package cn.wangqi.personal.redis;

import redis.clients.util.SafeEncoder;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class RedisUtil {
	@SuppressWarnings("unchecked")
	public static final <T extends Serializable> List<T> decode(List<byte[]> byteList) {
		List<T> objectList = new ArrayList<T>(byteList.size());
		for (byte[] bytes : byteList) {
			if (null != bytes) {
				T object = (T) decode(bytes);
				objectList.add((T) object);
			} else {
				objectList.add(null);
			}
		}
		return objectList;
	}

	@SuppressWarnings("unchecked")
	public static final <T extends Serializable> List<T> decode(List<byte[]> byteList, int offset, int size) {
		if (byteList.size() == 0 || (byteList.size() - 1) < offset) {
			return new ArrayList<T>(0);
		}
		if (offset < 0) {
			offset = 0;
		}
		List<T> objectList = new ArrayList<T>(byteList.size() - offset);
		for (int i = offset; i < byteList.size() && i < (offset + size); i++) {
			byte[] bytes = byteList.get(i);
			if (null != bytes) {
				T object = (T) decode(bytes);
				objectList.add((T) object);
			} else {
				objectList.add(null);
			}
		}
		return objectList;
	}

	public static final <T extends Serializable> byte[] encode(T obj) {
		byte[] bytes = null;
		try {
			ByteArrayOutputStream bout = new ByteArrayOutputStream();
			ObjectOutputStream out = new ObjectOutputStream(bout);
			out.writeObject(obj);
			bytes = bout.toByteArray();
		} catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeException("Error serializing object" + obj + " => " + e);
		}
		return bytes;
	}

	@SuppressWarnings("unchecked")
	public static final <T extends Serializable> T decode(byte[] bytes) {
		if (bytes == null) {
			return null;
		}
		T t = null;
		Exception thrown = null;
		try {
			ObjectInputStream oin = new ObjectInputStream(new ByteArrayInputStream(bytes));
			t = (T) oin.readObject();
		} catch (IOException e) {
			e.printStackTrace();
			thrown = e;
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			thrown = e;
		} catch (ClassCastException e) {
			e.printStackTrace();
			thrown = e;
		} finally {
			if (null != thrown) {
				throw new RuntimeException("Error decoding byte[] data to instantiate java object - "
						+ "data at key may not have been of this type or even an object", thrown);
			}
		}
		return t;
	}

	public static final <T extends Serializable> byte[][] encode(Map<String, T> map) {
		if (map == null) {
			return null;
		}
		byte[][] mappings = new byte[map.size() * 2][];
		int i = 0;
		for (Map.Entry<String, T> entry : map.entrySet()) {
			mappings[i++] = SafeEncoder.encode(entry.getKey());
			mappings[i++] = encode(entry.getValue());
		}

		return mappings;
	}

	public static final <T extends Serializable> byte[][] encode(T[] list) {
		if (list == null) {
			return null;
		}
		byte[][] bytes = new byte[list.length][];
		int i = 0;
		for (T item : list) {
			bytes[i++] = encode(item);
		}

		return bytes;
	}

}
